/**
 * 
 */
package x.java.tea;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author qiangli
 * 
 */
public class ObjectPropertyInjector extends ObjectInjector {

	public ObjectPropertyInjector(Object obj) {
		this.obj = obj;
	}

	public void setObject(Object obj) {
		this.obj = obj;
	}

	public void setBuf(Object obj) {
		Object v = getProperty(obj, id);
		setBuf(format(v, id));
	}

	/**
	 * Return a formatted string representation of the object v for the given id.
	 * The default implementation returns the result of toString method or an empty string
	 * if v is null.
	 * 
	 * Subclass should override this method and format v accordingly.
	 * 
	 * @param v
	 * @param id
	 * @return
	 */
	protected String format(Object v, String id) {
		if (v == null) {
			return "";
		}
		return v.toString();
	}

	/**
	 * Get the property by reflection in the following order and return the first value found:
	 * 1. field with the given id
	 * 2. method with the given id
	 * 3. method with the id prefixed with "get" or "is" after the initial letter is upper-cased
	 * 4. method with the id prefixed with "to" after the initial letter upper-cased.
	 * @param obj
	 * @param id
	 * @return
	 */
	protected Object getProperty(Object obj, String id) {
		Class<?> c = obj.getClass();
		Class<?>[] types = null;
		Object[] args = null;
		Object v = null;
		//1. instance field
		try {
			Field f = c.getField(id);
			v = f.get(obj);
			return v;
		} catch (Exception e) {
			// e.printStackTrace();
		}
		//2. method 
		try {
			Method m = c.getMethod(id, types);
			v = m.invoke(obj, args);
			return v;
		} catch (Exception e) {
			// e.printStackTrace();
		}
		//3. get/is method
		String ucn = Character.toUpperCase(id.charAt(0)) + id.substring(1);
		try {
			String n = "get" + ucn;
			Method m = c.getMethod(n, types);
			v = m.invoke(obj, args);
			return v;
		} catch (Exception e) {
			// e.printStackTrace();
		}
		try {
			String n = "is" + ucn;
			Method m = c.getMethod(n, types);
			v = m.invoke(obj, args);
			return v;
		} catch (Exception e) {
			// e.printStackTrace();
		}
		//4. to method
		try {
			String n = "to" + ucn;
			Method m = c.getMethod(n, types);
			v = m.invoke(obj, args);
			return v;
		} catch (Exception e) {
			// e.printStackTrace();
		}
		return v;
	}
}
